/*
 * ml20dll
 * This source code is under the GNU Public License (GPL).
 * Written by Ramiro Polla
 * Initial release: july 14th, 2005
 *
 * this dll reads ml20 files
 */

#include "ml20dll.h"

decoder_t *new_decoder( vstream_t *vstream, msn_t *msnt )
{
    BITMAPINFOHEADER ML20 = { 0x00000028, 0x00000000, 0x00000000, 0x0001, 0x000c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
    BITMAPINFOHEADER BITM = { 0x00000028, 0x00000000, 0x00000000, 0x0001, 0x0018, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 };

    decoder_t *ret;
    decoder_t tret;

    memset( &tret, 0x00, sizeof(decoder_t) );
    memcpy( &tret.BITM, &BITM, sizeof(BITMAPINFOHEADER) );
    tret.BITM.biHeight = vstream->height;
    tret.BITM.biWidth = vstream->width;
    tret.BITM.biSizeImage = vstream->height * vstream->width * 3;

    if( IS_SET( vstream->flags, VSTREAM_VC ) ) {
        struct wmv3bmi WMV3 = { { 0x0000002e, 0x00000140, 0x000000f0, 0x0001, 0x0018, FOURCC_WMV3, 0x038400, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x0f, 0xf1, 0x80, 0x01, 0x40, 0x0f } };
        FARPROC wmv3;
        HMODULE xis;

        if( !(xis = LoadLibrary( msnt->wmv )) )
            return FALSE;

        if( !(wmv3 = GetProcAddress( xis, "DriverProc" )) )
            return FALSE;

        memcpy( &tret.WMV3, &WMV3, sizeof(struct wmv3bmi) );

        ICInstall( ICTYPE_VIDEO, FOURCC_WMV3, (LPARAM) wmv3, NULL, ICINSTALL_FUNCTION );
        tret.hIC = ICOpen( ICTYPE_VIDEO, FOURCC_WMV3, ICMODE_DECOMPRESS );
        ICRemove( ICTYPE_VIDEO, FOURCC_WMV3, 0 );

        if( !tret.hIC )
            return FALSE;

        ICDecompressBegin( tret.hIC, &tret.WMV3, &tret.BITM );
    } else if( msnt->pid ) {
        INJDATA injdata = {
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            { 'm', 's', 'v', 'f', 'w', '3', '2', '.', 'd', 'l', 'l', '\0' },
            { 'I', 'C', 'O', 'p', 'e', 'n', '\0' },
            { 'I', 'C', 'I', 'n', 's', 't', 'a', 'l', 'l', '\0' },
            { 'I', 'C', 'D', 'e', 'c', 'o', 'm', 'p', 'r', 'e', 's', 's', '\0' },
            { 'I', 'C', 'C', 'l', 'o', 's', 'e', '\0' },
            { 'I', 'C', 'S', 'e', 'n', 'd', 'M', 'e', 's', 's', 'a', 'g', 'e', '\0' },
            { 'I', 'C', 'R', 'e', 'm', 'o', 'v', 'e', '\0' },
            { 0x00000028, 0x00000000, 0x00000000, 0x0001, 0x000c, 0x30324d4c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
            { 0x00000028, 0x00000000, 0x00000000, 0x0001, 0x0018, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
            0x00, 0x00,    0x00, 0x00, 0x00
            };

        memcpy( &tret.ML20, &ML20, sizeof(BITMAPINFOHEADER) );
        tret.ML20.biHeight = vstream->height;
        tret.ML20.biWidth = vstream->width;
        tret.ML20.biCompression = FOURCC_ML20;

        tret.injdata = malloc( sizeof(INJDATA) );
        memcpy( tret.injdata, &injdata, sizeof(INJDATA) );
        memcpy( &tret.injdata->BITM, &tret.BITM, sizeof(BITMAPINFOHEADER) );
        memcpy( &tret.injdata->ML20, &tret.ML20, sizeof(BITMAPINFOHEADER) );
        tret.injdata->ml20proc = msnt->procaddress;
        msnt->rp = OpenProcess( PROCESS_ALL_ACCESS, FALSE, msnt->pid );
        memcpy( &tret.injdata->msnt, msnt, sizeof(msn_t) );

        SET_BIT( tret.flags, DECODER_REMOTE );
        if( !startremotevideo( tret.injdata ) )
            return FALSE;
    } else {
        memcpy( &tret.ML20, &ML20, sizeof(BITMAPINFOHEADER) );
        tret.ML20.biHeight = vstream->height;
        tret.ML20.biWidth = vstream->width;
        tret.ML20.biCompression = FOURCC_LM20;

        ICInstall( ICTYPE_VIDEO, FOURCC_LM20, (LPARAM) msnt->procaddress, NULL, ICINSTALL_FUNCTION );
        tret.hIC = ICOpen( ICTYPE_VIDEO, FOURCC_LM20, ICMODE_DECOMPRESS );
        ICRemove( ICTYPE_VIDEO, FOURCC_LM20, 0 );

        if( !tret.hIC )
            return FALSE;

        ICDecompressBegin( tret.hIC, &tret.ML20, &tret.BITM );
    }

    tret.kol = malloc( tret.BITM.biSizeImage );
    if( tret.injdata )
        tret.injdata->out = tret.kol;
    tret.vstream = vstream;

    ret = calloc( 1, sizeof(decoder_t) );
    memcpy( ret, &tret, sizeof(decoder_t) );

    return ret;
}

void kill_decoder( decoder_t *decoder )
{
    if( !decoder )
        return;

    if( IS_SET( decoder->flags, DECODER_REMOTE ) ) {
        endremotevideo( decoder->injdata );
        CloseHandle( decoder->injdata->msnt.rp );
    }

    if( decoder->hIC ) {
        ICDecompressEnd( decoder->hIC );
        ICClose( decoder->hIC );
    }

    if( decoder->kol )
        free( decoder->kol );
    free( decoder );
}
